package service

import (
	"fabric-explorer/dao"
	"fabric-explorer/entity"
	"fmt"

	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric-protos-go/common"
	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
	"github.com/hyperledger/fabric-protos-go/msp"
	"github.com/hyperledger/fabric-protos-go/peer"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
)

//初始化交易数据
func InitTransactionData(blockDataList []entity.BlockData) {

	//遍历原始区块数据获得交易数据
	for _, blockData := range blockDataList {
		transactionList := GetTransactionFromBlock(blockData)
		for _, t := range transactionList {
			dao.InsertTransaction(t)
		}
	}
	//setTransactionNum()
}

//解析block数据成transaction
func GetTransactionFromBlock(block entity.BlockData) []entity.Transaction {
	transactionList := make([]entity.Transaction, 0)
	fmt.Print("-------------解析block---------------'\n")
	for _, v := range block.Data {
		//初始化transaction
		transaction := &entity.Transaction{}
		transaction.BlockNum = block.Num
		var envelope common.Envelope
		if err := proto.Unmarshal(v, &envelope); err != nil {
			fmt.Println(err)
			return transactionList
		}
		envelope.GetPayload()

		//获得payload
		var payload common.Payload
		err := proto.Unmarshal(envelope.GetPayload(), &payload)
		if err != nil {
			fmt.Println(err)
			return transactionList
		}

		//获得channelHeader,得到一些通道相关的数据
		var channelHeader common.ChannelHeader
		err = proto.Unmarshal(payload.Header.GetChannelHeader(), &channelHeader)
		if err != nil {
			fmt.Println(err)
			return transactionList
		}
		fmt.Printf("channelHeader.ChannelId: %v\n", channelHeader.ChannelId)
		fmt.Printf("channelHeader.TxId: %v\n", channelHeader.TxId)
		fmt.Printf("channelHeader.Timestamp: %v\n", channelHeader.Timestamp)
		fmt.Printf("channelHeader.Type: %v\n", common.HeaderType_name[channelHeader.Type])
		transaction.ChannelId = channelHeader.ChannelId
		transaction.TxId = channelHeader.TxId
		transaction.Timestamp = channelHeader.Timestamp.AsTime().UnixMilli()
		transaction.Type = common.HeaderType_name[channelHeader.Type]

		//签名header,得到交易发起人
		signatureHeader := &common.SignatureHeader{}
		err = proto.Unmarshal(payload.Header.SignatureHeader, signatureHeader)
		if err != nil {
			fmt.Println(err)
			return transactionList
		}
		creator := &msp.SerializedIdentity{}
		err = proto.Unmarshal(signatureHeader.Creator, creator)
		if err != nil {
			fmt.Println(err)
			return transactionList
		}
		fmt.Printf("creator.Mspid: %v\n", creator.Mspid)
		transaction.Creator = creator.Mspid

		//获得交易数据
		var transAction peer.Transaction
		err = proto.Unmarshal(payload.GetData(), &transAction)
		if err != nil {
			fmt.Println(err)
			return transactionList
		}
		//多个transactionAction
		for _, transactionAction := range transAction.GetActions() {
			var chaincodeActionPayload peer.ChaincodeActionPayload
			err = proto.Unmarshal(transactionAction.GetPayload(), &chaincodeActionPayload)
			if err != nil {
				fmt.Println(err)
				return transactionList
			}
			//获得背书节点名称
			for _, e := range chaincodeActionPayload.Action.Endorsements {
				endorser := &msp.SerializedIdentity{}
				err = proto.Unmarshal(e.Endorser, endorser)
				if err != nil {
					fmt.Println(err)
					return transactionList
				}
				fmt.Printf("endorser.Mspid: %v\n", endorser.Mspid)
				transaction.Endorser = append(transaction.Endorser, endorser.Mspid)
			}

			//ChaincodeProposalPayload 解析输入 链码，参数
			var chaincodeProposalPayload peer.ChaincodeProposalPayload
			err = proto.Unmarshal(chaincodeActionPayload.GetChaincodeProposalPayload(), &chaincodeProposalPayload)
			if err != nil {
				fmt.Println(err)
				return transactionList
			}
			var input peer.ChaincodeInvocationSpec
			err = proto.Unmarshal(chaincodeProposalPayload.GetInput(), &input)
			if err != nil {
				fmt.Println(err)
				return transactionList
			}
			//交易发起的参数列表
			if input.ChaincodeSpec != nil && input.ChaincodeSpec.Input.Args != nil {
				for i, v := range input.ChaincodeSpec.Input.Args {
					fmt.Printf("第%v个参数，值：%s\n", i, v)
					transaction.Args = append(transaction.Args, string(v))
				}
			}

			//一次交易的内部输入输出
			var proposalResponsePayload peer.ProposalResponsePayload
			err = proto.Unmarshal(chaincodeActionPayload.Action.ProposalResponsePayload, &proposalResponsePayload)
			if err != nil {
				fmt.Println(err)
			}
			//获得ProposalHash
			fmt.Printf("proposalResponsePayload.ProposalHash: %x\n", proposalResponsePayload.ProposalHash)
			transaction.ProposalHash = fmt.Sprintf("%x", proposalResponsePayload.ProposalHash)

			var chaincodeAction peer.ChaincodeAction
			err = proto.Unmarshal(proposalResponsePayload.Extension, &chaincodeAction)
			if err != nil {
				fmt.Println(err)
			}
			if chaincodeAction.ChaincodeId != nil {
				//获得chaincode数据
				fmt.Printf("chaincodeAction.ChaincodeId.Name: %v\n", chaincodeAction.ChaincodeId.Name)
				fmt.Printf("chaincodeAction.ChaincodeId.Version: %v\n", chaincodeAction.ChaincodeId.Version)
				transaction.Chaincode = chaincodeAction.ChaincodeId.Name
				transaction.ChaincodeVersion = chaincodeAction.ChaincodeId.Version
			}

			var txrwset rwset.TxReadWriteSet
			err = proto.Unmarshal(chaincodeAction.Results, &txrwset)
			if err != nil {
				fmt.Println(err)
				return transactionList
			}
			fmt.Printf("txrwset.DataModel.String(): %v\n", txrwset.DataModel.String())
			for i, v := range txrwset.NsRwset {
				fmt.Printf("i: %v\n", i)
				fmt.Printf("v.Namespace: %v\n", v.Namespace)
				var kvset kvrwset.KVRWSet
				err = proto.Unmarshal(v.Rwset, &kvset)
				if err != nil {
					fmt.Println(err)
					return transactionList
				}
				fmt.Printf("kvset.Reads: %v\n", kvset.Reads)
				fmt.Printf("kvset.Writes: %v\n", kvset.Writes)
				transaction.Reads = append(transaction.Reads, fmt.Sprintf("%v", kvset.Reads))
				transaction.Writes = append(transaction.Writes, fmt.Sprintf("%v", kvset.Writes))
			}
			transactionList = append(transactionList, *transaction)
		}
	}
	//翻转
	for i := len(transactionList)/2 - 1; i >= 0; i-- {
		opp := len(transactionList) - 1 - i
		transactionList[i], transactionList[opp] = transactionList[opp], transactionList[i]
	}
	return transactionList
}

//删除所有的transaction
func DeleteAllTransaction() {
	dao.DeleteTransaction(bson.D{})
}

//查询数量
func GetTransactionNum(selecter bson.D) int64 {
	return dao.GetTransactionNum(selecter)
}

//获得所有的Transaction
func GetAllTransaction() []entity.Transaction {
	return dao.FindTransactionList(bson.D{})
}

//获得的TransactionList
func FindTransactionList(selector bson.D) []entity.Transaction {
	return dao.FindTransactionList(selector)
}

//查询一个Transaction
func FindTransactionOne(selecter bson.D) entity.Transaction {
	return dao.FindTransactionOne(selecter)
}

//查询Transaction的page
func FindTransactionListPage(selecter bson.D, options *options.FindOptions) []entity.Transaction {
	return dao.FindTransactionListPage(selecter, options)
}
